package com.cherry.androidviewdemo.widget

import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.ViewGroup
import kotlin.math.ceil

/**
 * 简单的瀑布流
 * @author DongMS
 * @since 2020/5/21
 */
class WaterfallLayout : ViewGroup {

    var column = 3
    var hSpace = 20
    var vSpace = 20
    private var childWidth = 0
    //top[columns]来保存当前每列的高度，以实时找到最短的高度的位置，将新增的图片放在那里
    private var topArray = FloatArray(column)

    constructor (context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)

        val widthMode = MeasureSpec.getMode(widthMeasureSpec)
        val widthSize = MeasureSpec.getSize(widthMeasureSpec)

        //内部调用 measureChild() 对每一个子视图进行 measure 操作
        measureChildren(widthMeasureSpec, heightMeasureSpec)

        //计算每张图片的宽度，每张图片的宽度一致
        childWidth = (widthSize - (column - 1) * hSpace) / column

        //计算控件的总宽度
        val childCount = childCount
        val width = if (childCount < column) {
            childWidth * childCount + hSpace * (childCount - 1)
        } else {
            widthSize
        }

        //计算控件的总高度
        //清空数组，以免影响上次的计算结果
        clearTop()
        //数组来标识每列在添加图片后的高度，以便在每次插入图片时，找到当前最短的列
        for (i in 0 until childCount) {
            val childView = getChildAt(i)
            val childHeight = childView.measuredHeight * (childWidth * 1f / childView.measuredWidth)
            val minHeightColumn = getMinHeightColumn()

            //改进的代码，在测量的时候保存这些参数,layout不用再次计算
            val lp = childView.layoutParams as WaterfallLayoutParams
            lp.left = minHeightColumn * (hSpace + childWidth) * 1f
            lp.top = topArray[minHeightColumn]
            lp.right = lp.left + childWidth
            lp.bottom = lp.top + childHeight

            topArray[minHeightColumn] += vSpace + childHeight
        }

        //确定控件高度
        val height = getMaxHeight()

        setMeasuredDimension(if (widthMode == MeasureSpec.EXACTLY) widthSize else width,
                height?.toInt() ?: 0)

    }

    private fun getMaxHeight() = topArray.max()

    private fun getMinHeightColumn(): Int {
        var minColumn = 0
        topArray.forEachIndexed { index, value ->
            if (value < topArray[minColumn]) {
                minColumn = index
            }
        }
        return minColumn
    }

    /**
     * 每次在计算高度之前，我们应该先把top[]数组清空，以防上次的数据影响这次的计算
     */
    private fun clearTop() {
        topArray.forEachIndexed { index, _ -> topArray[index] = 0f }
    }


    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        val childCount = childCount
//        clearTop()
        for (i in 0 until childCount) {
            val childView = getChildAt(i)
//            val childHeight = childView.measuredHeight * (childWidth / childView.measuredWidth)
//            val minHeightColumn = getMinHeightColumn()
//            val l = minHeightColumn * (hSpace + childWidth)
//            val t = topArray[minHeightColumn]
//            val r = l + childWidth
//            val b = t + childHeight
//
//            topArray[minHeightColumn] += vSpace + childView.measuredHeight
//            childView.layout(l, t, r, b)

            val lp = childView.layoutParams as WaterfallLayoutParams
            childView.layout(lp.left.toInt(), lp.top.toInt(), lp.right.toInt(), lp.bottom.toInt())
        }

    }

    //保存childView layout需要的位置参数
    override fun checkLayoutParams(p: LayoutParams?): Boolean {
        return p is WaterfallLayoutParams
    }

    override fun generateLayoutParams(p: LayoutParams?): LayoutParams {
        return WaterfallLayoutParams(p)
    }

    override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams {
        return WaterfallLayoutParams(context, attrs)
    }

    override fun generateDefaultLayoutParams(): LayoutParams {
        return WaterfallLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
    }

    class WaterfallLayoutParams : LayoutParams {

        var left = 0f
        var right = 0f
        var top = 0f
        var bottom = 0f

        constructor(width: Int, height: Int) : super(width, height)

        constructor(c: Context, attrs: AttributeSet?) : super(c, attrs)

        constructor(source: LayoutParams?) : super(source)

    }

}